package com.shm.leetcode;

import java.util.HashSet;
import java.util.Set;

/**
 * 997. 找到小镇的法官
 * 在一个小镇里，按从 1 到 n 为 n 个人进行编号。传言称，这些人中有一个是小镇上的秘密法官。
 *
 * 如果小镇的法官真的存在，那么：
 *
 * 小镇的法官不相信任何人。
 * 每个人（除了小镇法官外）都信任小镇的法官。
 * 只有一个人同时满足条件 1 和条件 2 。
 * 给定数组 trust，该数组由信任对 trust[i] = [a, b] 组成，表示编号为 a 的人信任编号为 b 的人。
 *
 * 如果小镇存在秘密法官并且可以确定他的身份，请返回该法官的编号。否则，返回 -1。
 *
 *
 *
 * 示例 1：
 *
 * 输入：n = 2, trust = [[1,2]]
 * 输出：2
 * 示例 2：
 *
 * 输入：n = 3, trust = [[1,3],[2,3]]
 * 输出：3
 * 示例 3：
 *
 * 输入：n = 3, trust = [[1,3],[2,3],[3,1]]
 * 输出：-1
 * 示例 4：
 *
 * 输入：n = 3, trust = [[1,2],[2,3]]
 * 输出：-1
 * 示例 5：
 *
 * 输入：n = 4, trust = [[1,3],[1,4],[2,3],[2,4],[4,3]]
 * 输出：3
 *
 *
 * 提示：
 *
 * 1 <= n <= 1000
 * 0 <= trust.length <= 104
 * trust[i].length == 2
 * trust[i] 互不相同
 * trust[i][0] != trust[i][1]
 * 1 <= trust[i][0], trust[i][1] <= n
 * @author SHM
 */
public class FindJudge {
    public int findJudge(int n, int[][] trust) {
        int ans=-1;
        Set<Integer> cnt = new HashSet<>();
        int[] arr = new int[n+1];
        for (int[] ints : trust) {
            arr[ints[1]]++;
            cnt.add(ints[0]);
        }
        for (int i = 1; i < n+1; i++) {
            if (arr[i]==n-1&&!cnt.contains(i)){
                return i;
            }
        }
        return ans;
    }


    /**
     * 预备知识
     * 本题需要用到有向图中节点的入度和出度的概念。在有向图中，一个节点的入度是指向该节点的边的数量；而一个节点的出度是从该节点出发的边的数量。
     *
     * 方法一：计算各节点的入度和出度
     * 思路及解法
     *
     * 题干描述了一个有向图。每个人是图的节点，\textit{trust}trust 的元素 \textit{trust}[i]trust[i] 是图的有向边，从 \textit{trust}[i][0]trust[i][0] 指向 \textit{trust}[i][1]trust[i][1]。我们可以遍历 \textit{trust}trust，统计每个节点的入度和出度，存储在 \textit{inDegrees}inDegrees 和 \textit{outDegrees}outDegrees 中。
     *
     * 根据题意，在法官存在的情况下，法官不相信任何人，每个人（除了法官外）都信任法官，且只有一名法官。因此法官这个节点的入度是 n-1n−1, 出度是 00。
     *
     * 我们可以遍历每个节点的入度和出度，如果找到一个符合条件的节点，由于题目保证只有一个法官，我们可以直接返回结果；如果不存在符合条件的点，则返回 -1−1。
     *
     * 复杂度分析
     *
     * 时间复杂度：O(n+m)O(n+m)，其中 mm 是 \textit{trust}trust 的长度。首先需要遍历 \textit{trust}trust 计算出 \textit{inDegrees}inDegrees 和 \textit{outDegrees}outDegrees，然后需要遍历 \textit{inDegrees}inDegrees 和 \textit{outDegrees}outDegrees 来确定法官。
     *
     * 空间复杂度：O(n)O(n)。记录各个节点的入度和出度需要 O(n)O(n) 的空间。
     *
     * 作者：LeetCode-Solution
     * 链接：https://leetcode-cn.com/problems/find-the-town-judge/solution/zhao-dao-xiao-zhen-de-fa-guan-by-leetcod-0dcg/
     * @param n
     * @param trust
     * @return
     */
        public int findJudge_1(int n, int[][] trust) {
            int[] inDegrees = new int[n + 1];
            int[] outDegrees = new int[n + 1];
            for (int[] edge : trust) {
                int x = edge[0], y = edge[1];
                ++inDegrees[y];
                ++outDegrees[x];
            }
            for (int i = 1; i <= n; ++i) {
                if (inDegrees[i] == n - 1 && outDegrees[i] == 0) {
                    return i;
                }
            }
            return -1;
        }

}
